home *** CD-ROM | disk | FTP | other *** search
/ TPUG - Toronto PET Users Group / TPUG Users Group CD / TPUG Users Group CD.iso / AMIGA / AMICUS / AMICUS26.ADF / SoundScape / AztecExamples / crossfade.c < prev    next >
C/C++ Source or Header  |  1989-01-26  |  11KB  |  533 lines

  1. /*    CROSSFADE.C    Cross fade loop generator for the
  2.             SoundScape sampler.
  3.  
  4.     (c) 1987     Todor Fay
  5.  
  6.     Aztec C version.
  7. */
  8.     
  9. #include "exec/exec.h"
  10. #include "exec/types.h"
  11. #include "intuition/intuition.h"
  12. #include "soundscape.h"
  13. #include "sampler.h"
  14.  
  15. /*    Cross Fade Icon for Patch Panel: */
  16.  
  17. UWORD crossfadedata[] = {    /* 36 x 11 */ 
  18. 0,    0,    0,    
  19. 16383,    65535,    49152,    
  20. 511,    65528,    0,    
  21. 15887,    65287,    49152,    
  22. 16368,    24831,    49152,    
  23. 16383,    40959,    49152,    
  24. 16368,    24831,    49152,    
  25. 15887,    65287,    49152,    
  26. 511,    65528,    0,    
  27. 16383,    65535,    49152,    
  28. 0,    0,    0,    
  29. 65535,    65535,    61440,    
  30. 49152,    4,    12288,    
  31. 49152,    57544,    12288,    
  32. 49153,    61700,    28672,    
  33. 55792,    24812,    61440,    
  34. 65535,    40959,    61440,    
  35. 55792,    24812,    61440,    
  36. 49153,    61444,    28672,    
  37. 49152,    57544,    12288,    
  38. 49152,    4,    12288,    
  39. 65535,    65535,    61440,    
  40. };
  41.  
  42. struct Image crossfadeimage = 
  43.     { 0,0,36,11,2,crossfadedata,3,0,0 };
  44.  
  45. /*    Edit window.  This has the gadgets for selecting 
  46.     sampler channel and octave, and Doing and Undoing
  47.     the cross fade.  These intuition data structures
  48.     were generated with Power Windows.
  49. */
  50.  
  51. USHORT BorderVectors1[] = {0,0,107,0,107,10,0,10,0,0};
  52. struct Border Border1 = {
  53.     -2,-1,
  54.     3,0,JAM1,
  55.     5,
  56.     BorderVectors1,
  57.     NULL
  58. };
  59.  
  60. struct IntuiText IText1 = {
  61.     1,0,JAM2,
  62.     33,1,
  63.     NULL,
  64.     "Undo",
  65.     NULL
  66. };
  67.  
  68. struct Gadget UndoGadget = {
  69.     NULL,
  70.     23,55,
  71.     104,9,
  72.     GADGHCOMP,
  73.     RELVERIFY,
  74.     BOOLGADGET,
  75.     (APTR)&Border1,
  76.     NULL,
  77.     &IText1,
  78.     0,
  79.     NULL,
  80.     8,
  81.     NULL
  82. };
  83.  
  84. UBYTE SIBuffer7[4] =
  85.     "5";
  86. struct StringInfo GadgetSI7 = {
  87.     SIBuffer7,
  88.     NULL,
  89.     0,
  90.     4,
  91.     0,
  92.     0,0,0,0,0,
  93.     0,
  94.     5,
  95.     NULL
  96. };
  97.  
  98. USHORT BorderVectors2[] = {0,0,35,0,35,9,0,9,0,0};
  99. struct Border Border2 = {
  100.     -2,-1,
  101.     1,0,JAM1,
  102.     5,
  103.     BorderVectors2,
  104.     NULL
  105. };
  106.  
  107. struct IntuiText IText2 = {
  108.     2,0,JAM2,
  109.     -60,0,
  110.     NULL,
  111.     "Octave",
  112.     NULL
  113. };
  114.  
  115. struct Gadget OctaveGadget = {
  116.     &UndoGadget,
  117.     95,28,
  118.     32,8,
  119.     GADGHCOMP,
  120.     LONGINT+RELVERIFY+STRINGCENTER,
  121.     STRGADGET,
  122.     (APTR)&Border2,
  123.     NULL,
  124.     &IText2,
  125.     0,
  126.     (APTR)&GadgetSI7,
  127.     7,
  128.     NULL
  129. };
  130.  
  131. UBYTE SIBuffer6[4] =
  132.     "1";
  133. struct StringInfo GadgetSI6 = {
  134.     SIBuffer6,
  135.     NULL,
  136.     0,
  137.     4,
  138.     0,
  139.     0,0,0,0,0,
  140.     0,
  141.     1,
  142.     NULL
  143. };
  144.  
  145. USHORT BorderVectors3[] = {0,0,35,0,35,9,0,9,0,0};
  146. struct Border Border3 = {
  147.     -2,-1,
  148.     1,0,JAM1,
  149.     5,
  150.     BorderVectors3,
  151.     NULL
  152. };
  153.  
  154. struct IntuiText IText3 = {
  155.     2,0,JAM2,
  156.     -67,0,
  157.     NULL,
  158.     "Channel",
  159.     NULL
  160. };
  161.  
  162. struct Gadget ChannelGadget = {
  163.     &OctaveGadget,
  164.     95,15,
  165.     32,8,
  166.     GADGHCOMP,
  167.     LONGINT+RELVERIFY+STRINGCENTER,
  168.     STRGADGET,
  169.     (APTR)&Border3,
  170.     NULL,
  171.     &IText3,
  172.     0,
  173.     (APTR)&GadgetSI6,
  174.     6,
  175.     NULL
  176. };
  177.  
  178. USHORT BorderVectors4[] = {0,0,107,0,107,10,0,10,0,0};
  179. struct Border Border4 = {
  180.     -2,-1,
  181.     3,0,JAM1,
  182.     5,
  183.     BorderVectors4,
  184.     NULL
  185. };
  186.  
  187. struct IntuiText IText4 = {
  188.     1,0,JAM2,
  189.     12,1,
  190.     NULL,
  191.     "Cross Fade",
  192.     NULL
  193. };
  194.  
  195. struct Gadget CrossFadeGadget = {
  196.     &ChannelGadget,
  197.     23,41,
  198.     104,9,
  199.     GADGHCOMP,
  200.     RELVERIFY,
  201.     BOOLGADGET,
  202.     (APTR)&Border4,
  203.     NULL,
  204.     &IText4,
  205.     0,
  206.     NULL,
  207.     5,
  208.     NULL
  209. };
  210.  
  211. /* Gadget list */
  212.  
  213. struct NewWindow NewWindowStructure = {
  214.     0,0,
  215.     152,72,
  216.     0,1,
  217.     GADGETUP+CLOSEWINDOW+RAWKEY,
  218.     WINDOWSIZING+WINDOWDRAG+WINDOWDEPTH+WINDOWCLOSE
  219.     +ACTIVATE,
  220.     &CrossFadeGadget,
  221.     NULL,
  222.     " X Fade ",
  223.     NULL,
  224.     NULL,
  225.     30,20,
  226.     152,72,
  227.     WBENCHSCREEN
  228. };
  229.  
  230. unsigned short thisport;
  231.  
  232. opencode(direction)
  233.  
  234. /*    There is nothing to be initialised.  However,
  235.     it would be nice to connect the console
  236.     keyboard to the sampler so the user can test
  237.     the cross fade loops, so make an OpenLink call.
  238.     FindMidiPort returns the port id, given the
  239.     name of the port.  Actually, these two ports
  240.     have ids that are hard coded into SoundScape.
  241.     This is an example what you should do with 
  242.     modules that are independantly loaded into 
  243.     the system.
  244. */
  245.  
  246. unsigned char direction;
  247.  
  248. {
  249.     enteraztec();
  250.     OpenLink(FindMidiPort("console keyboard"),
  251.     FindMidiPort("sampler"));
  252.     leaveaztec();
  253.     return(1);
  254. }
  255.  
  256. closecode(direction)
  257.  
  258. unsigned char direction;
  259.  
  260. {
  261.     return(1);
  262. }
  263.  
  264. clearsounddata(sounddata)
  265.  
  266. /*    This routine frees up the sample buffer belonging
  267.     to the SoundData structure 'sounddata'.
  268. */
  269.  
  270. struct SoundData *sounddata;
  271.  
  272. {
  273.     if (sounddata->data) 
  274.     FreeMem(sounddata->data,sounddata->length);
  275.     sounddata->data = 0;
  276.     sounddata->length = 0;
  277.     sounddata->loopstart = 0;
  278.     sounddata->loopend = 0;
  279.     sounddata->start = 0;
  280. }
  281.  
  282. crossfade(sounddata)
  283.  
  284. /*    This, the cross fade routine, operates on a 
  285.     SoundData structure.
  286.  
  287.     The cross fade is done on the region of the
  288.     sample between the two loop points.  The
  289.     sample prior to the loop start is gradually
  290.     mixed in until it is in full force by the
  291.     end of the loop.  
  292.  
  293.     This is very straight forward, the only problem
  294.     encountered is a sample with a loop that 
  295.     is longer than the part leading into the
  296.     loop.  This is solved by having the cross fade
  297.     section be shorter - the length of the lead
  298.     in section.
  299. */
  300.     
  301. struct SoundData *sounddata;
  302.  
  303. {
  304.     char *sample;        /* Points to sample */
  305.     unsigned short loop;    /* Length of loop. */
  306.     unsigned short crosslength;    /* Length of cross fade. */
  307.     unsigned short start;    /* Start point. */
  308.     long result;        /* Intermediate result. */
  309.     unsigned short a,b;        /* Indexes into sample. */
  310.     unsigned short j;        /* Loop index. */
  311.     
  312.     loop = sounddata->loopend - sounddata->loopstart;
  313.     sample = &sounddata->data[sounddata->start];
  314.     start = sounddata->loopstart - sounddata->start;
  315.  
  316. /*    If the loop is greater than the start segment, set
  317.     the crossfade to cover the last part of the loop,
  318.     equal to the starting segment.
  319. */
  320.  
  321.     if (loop > start) {
  322.     crosslength = start;
  323.     a = 0;
  324.     b = loop;
  325.     }
  326.  
  327. /*    Otherwise, set the crossfade to cover the entire
  328.     loop.
  329. */
  330.  
  331.     else {
  332.     crosslength = loop;
  333.     a = start - loop;
  334.     b = start;
  335.     }
  336.     for (j = 0; j < crosslength; j++ ) {
  337.     result = (j * sample[a]);
  338.     result += (crosslength - j) * sample[b];
  339.     result = result / crosslength;
  340.     sample[b] = result;
  341.     a++;
  342.     b++;
  343.     }
  344. }
  345.  
  346. void useredit()
  347.  
  348. /*    This routine is called whenever the user clicks
  349.     twice on the cross fade icon.  A window is opened
  350.     and four gadgets are presented.  Two string
  351.     gadgets allow the user to select the octave and
  352.     channel of the sample they'd like to work on.
  353.     Two boolean gadgets are used to command the
  354.     cross fade and undo operations.
  355.  
  356.     There are two SoundData structures.  OldSound
  357.     is used to keep an old copy of the sample
  358.     around for undoing.  CFSound is used to hold
  359.     the sample that gets cross faded.
  360.  
  361.     RAWKEY events are passed on to the console
  362.     keyboard with the OutConsole command.
  363.     This is so the user can test the changed sound
  364.     without having to click on another window to
  365.     enable the Console Keyboard.
  366. */
  367.  
  368. {
  369.     struct IntuiMessage *message;
  370.     struct SoundData *oldsound, *cfsound;
  371.     short code, class;
  372.     struct Gadget *gadget;
  373.     struct Window *window;
  374.     short octave = 5;
  375.     short channel = 0;
  376.     oldsound = (struct SoundData *) 
  377.     AllocMem(sizeof(*oldsound),MEMF_CLEAR);
  378.     if (!oldsound) return;
  379.     cfsound = (struct SoundData *) 
  380.     AllocMem(sizeof(*cfsound),MEMF_CLEAR);
  381.     if (!cfsound) {
  382.     FreeMem(oldsound,sizeof(*oldsound));
  383.     return;
  384.     }
  385.     window = (struct Window *) 
  386.     OpenWindow(&NewWindowStructure);
  387.     while (window) {
  388.     while (!(message = (struct IntuiMessage *) 
  389.       GetMsg(window->UserPort)))
  390.         WaitPort(window->UserPort);
  391.     class = message->Class;
  392.     code = message->Code;
  393.     gadget = (struct Gadget *) message->IAddress;
  394.     ReplyMsg(message);
  395.     if (class == CLOSEWINDOW) break;
  396.     if (class == RAWKEY) OutConsole(code);
  397.     if (class == GADGETUP) {
  398.         switch (gadget->GadgetID) {
  399.         case 5 :
  400.  
  401. /*    The crossfade gadget.  Get the sample, using 
  402.     GetSoundData, and put it in cfsound.  Clear
  403.     the undo buffer (oldsound) and get the same
  404.     sample loaded into it.  Call crossfade to alter
  405.     cfsound, then install it in the sampler with
  406.     a call to SetSoundData.
  407.     Then, clear out cfsound.
  408. */
  409.     
  410.             if (!(GetSoundData(channel,
  411.               octave,cfsound))) {
  412.             clearsounddata(oldsound);
  413.             if (GetSoundData(channel,
  414.               octave,oldsound)) {
  415.                 oldsound->data = 0;
  416.             }
  417.             crossfade(cfsound);
  418.             SetSoundData(channel,octave,cfsound);
  419.             clearsounddata(cfsound);
  420.             }
  421.             break;
  422.         case 6 :
  423.  
  424. /*    This gadget simply sets the channel of the sampler
  425.     that we are looking at.  Also, clear the undo buffer.
  426. */
  427.  
  428.             channel = (GadgetSI6.LongInt - 1) & 0x0F;
  429.             clearsounddata(oldsound);
  430.             break;
  431.         case 7 :
  432.  
  433. /*    This gadget sets the octave of the sample we are
  434.     looking at.  Clear the undo buffer.
  435. */
  436.  
  437.             octave = GadgetSI7.LongInt;
  438.             if (octave < 0) octave = 0;
  439.             if (octave > 9) octave = 9;
  440.             clearsounddata(oldsound);
  441.             break;
  442.         case 8 :
  443.  
  444. /*    This is the undo command.  Simply give the undo
  445.     buffer to the sampler, then clear the undo buffer.
  446. */
  447.  
  448.             if (oldsound->data) {
  449.             SetSoundData(channel,octave,oldsound);
  450.             clearsounddata(oldsound);
  451.             }
  452.             break;
  453.         }
  454.     }
  455.     }
  456.     CloseWindow(window);
  457.     clearsounddata(oldsound);
  458.     clearsounddata(cfsound);
  459.     FreeMem(oldsound,sizeof(*oldsound));
  460.     FreeMem(cfsound,sizeof(*cfsound));
  461. }
  462.  
  463. editcode(direction,command,buffer)
  464.  
  465. /*    This is the edit routine provided to SoundScape 
  466.     in the AddMidiPort call.
  467.  
  468.     There is nothing in the way of data structures 
  469.     that we would like any other modules to access,
  470.     nor is there anything to save or load with
  471.     environment loads and save.  So, the GETSTATE, 
  472.     SETSTATE, SAVESTATE, and LOADSTATE commands are 
  473.     all ignored and the sample's length is set to
  474.     0.
  475.  
  476.     However, USEREDIT indicates the user has clicked 
  477.     twice on the cross fade icon and would like to 
  478.     work with it. In that case, call the routine 
  479.     'useredit' which puts up a window and lets the
  480.     user do that wild cross fade thing.
  481.     
  482. */
  483.  
  484. char direction, command;
  485. long *buffer;
  486.  
  487. {
  488.     static char not_editing = 1;
  489.     enteraztec();
  490.     *buffer = 0;
  491.     switch (command) {
  492.     case USEREDIT :
  493.         if (not_editing) {
  494.         not_editing = 0;
  495.         useredit();
  496.         not_editing = 1;
  497.         }
  498.         break;
  499.     }
  500.     leaveaztec();
  501. }
  502.         
  503. /*    The main program is simple.  Just open SoundScape to
  504.     get the address of the library vector, then close
  505.     the library (since this is a module and usually is
  506.     invoked by SoundScape when the first program opens
  507.     SoundScape, if it keeps the library count up, there
  508.     will be no way to close SoundScape.)
  509.     Check the version number.  If it's below 2, this
  510.     SoundScape Sampler module doesn't support having
  511.     samples changed, so quit.
  512.     Else, add the module's port and wait for SoundScape
  513.     to shut it down.
  514. */
  515.  
  516. long SoundScapeBase;
  517. long IntuitionBase;
  518.  
  519. main() {
  520.     SoundScapeBase = OpenLibrary("soundscape.library",0);
  521.     if (SoundScapeBase) {
  522.     IntuitionBase = OpenLibrary("intuition.library",0);
  523.     CloseLibrary(SoundScapeBase);
  524.     if (Version() > 1) {
  525.         thisport = AddMidiPort(opencode,closecode,
  526.         editcode,0,&crossfadeimage,0,-1,"cross fade");    
  527.         SetTaskPri(FindTask(0),-20);
  528.         while (MidiPort(thisport)) Delay(100);
  529.     }
  530.     CloseLibrary(IntuitionBase);
  531.     }
  532. }
  533.